package org.ainlolcat.ainscience.statistics.handlers.fitting.functions;

import org.apache.commons.math.optimization.fitting.ParametricRealFunction;

/**
* @author ainlolcat
*         Date: 5/9/13
*/
public class GaussFunction implements ParametricRealFunction {

    // y0 + (A/(w*Math.sqrt(Math.PI/2)))*Math.exp(-2 * Math.pow(dx, 2) / (Math.pow(w, 2)));
    //0 - y0
    //1 - A
    //2 - w
    //3 - x0
    public double value(double x, double[] parameters) {
        return parameters[0] +
                parameters[1]/(parameters[2]*Math.sqrt(Math.PI/2))*
                        Math.exp(-2 * Math.pow((x-parameters[3]), 2) / (Math.pow(parameters[2], 2)));
    }

    public double[] gradient(double x, double[] doubles) {
        double[] gradientVector = new double[doubles.length];
        double dx = doubles[3]-x;
        double EXP_VALUE = Math.exp(-2 * Math.pow(dx, 2) / (Math.pow(doubles[2], 2)));      //exp(-2*dx^2/w^2)
        double OVER_W_PI_SQUARED = 1 /(doubles[2]*Math.sqrt(Math.PI/2));                    //1/[w*sqrt(PI)]
        double A_OVER_W_PI_SQUARED = doubles[1]*OVER_W_PI_SQUARED;                          //A/[w*sqrt(PI)]

        gradientVector[0] = 1;                                                              //dF/dy0
        gradientVector[1] = OVER_W_PI_SQUARED * EXP_VALUE;                                  //dF/dA
        gradientVector[2] =                                                                 //dF/dw
                (
                        (-1)*doubles[1]/(Math.pow(doubles[2],2)*Math.sqrt(Math.PI/2))
                                +
                                A_OVER_W_PI_SQUARED * (-2*dx*dx)*(-2/Math.pow(doubles[2],3))
                )*
                        EXP_VALUE;
        gradientVector[3] =                                                                 //dF/dx0
                A_OVER_W_PI_SQUARED
                        *
                        (-2/Math.pow(doubles[2],2))*(-2*dx)
                        *
                        EXP_VALUE;
        return gradientVector;
    }
}
